#include "stdafx.h"
#include "FPTMemoFile.h"
#include <math.h>

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

IMPLEMENT_DYNAMIC(CFPTMemoFile, CMemoFile)

CFPTMemoFile::CFPTMemoFile()
{

}

CFPTMemoFile::~CFPTMemoFile()
{
	Close();
}

BOOL CFPTMemoFile::Open(LPCTSTR lpszName, UINT nOpenFlag)
{
	if (!lpszName)
		return FALSE;
	nOpenFlag = nOpenFlag | CFile::typeBinary;

	// Re-open is invalid
	if (IsOpen())
	{
		return FALSE;
	}


// TRY
// {
	DBF_CHECK_ERROR(
		CFile::Open(lpszName, nOpenFlag), TG_DBF_ERROR_MEMO_OPEN);

	DBF_CHECK_ERROR(
		ReadHeader(),TG_DBF_ERROR_MEMO_HEAD_READ);

	DBF_CHECK_ERROR(m_nBlockSize > 0,TG_DBF_ERROR_MEMO_BLOCK_SIZE);

	m_bOpen = TRUE;
// }
// CATCH(CFileException, e)
// {
// 	e->ReportError();
// 	e->Delete();
// 	Close();
// }
// END_CATCH
	return TRUE;
}

void CFPTMemoFile::Close()
{
	if(m_bOpen)
		CMemoFile::Close();
}

UINT CFPTMemoFile::GetMemoFileType()
{
	return MEMO_TYPE_FOXPRO;
}

BOOL CFPTMemoFile::ReadHeader()
{
	if (!m_hFile)
		return FALSE;
TRY
{
	Seek(0, CFile::begin);

	if(Read(&m_FPTHead, sizeof(FPT_HEAD)) != sizeof(FPT_HEAD))
		return FALSE;

	m_nNextBlock = SWAP_DWORD_BYTE(m_FPTHead.next_block);
	m_nBlockSize = SWAP_WORD_BYTE(m_FPTHead.block_size);

	return TRUE;
}
CATCH(CFileException, e)
{
	e->ReportError();
	e->Delete();

} END_CATCH

	return FALSE;
}

BOOL CFPTMemoFile::WriteHeader()
{
	if (!m_hFile)
		return FALSE;

TRY
{
	Seek(0, CFile::begin);

	Write(&m_FPTHead, sizeof(FPT_HEAD));

	return TRUE;
}
CATCH(CFileException, e)
{
	e->ReportError();
	e->Delete();

} END_CATCH

	return FALSE;
}

BOOL CFPTMemoFile::ReadMemoRecord(DBF_ULONG lOffsetRec, DBF_LONG& nLen, CTDbfString& strMemo)
{
	if (lOffsetRec < 0)
		return FALSE;

	strMemo = "";

	if(!IsOpen())
		return FALSE;

// TRY
// {
	DBF_LONG  nLenMemo = 0;

	Seek(lOffsetRec * m_nBlockSize + sizeof(DBF_LONG),CFile::begin);

	DBF_CHECK_ERROR(
		Read(&nLenMemo, sizeof(nLenMemo)) == sizeof(DBF_LONG),
		TG_DBF_ERROR_MEMO_FIELD_READ);

	nLenMemo = SWAP_DWORD_BYTE(nLenMemo);

	DBF_CHECK_ERROR(nLenMemo > 0,TG_DBF_ERROR_MEMO_FIELD_READ);

	char* buffer = new char[nLenMemo+1]/*strMemo.GetBuffer(nLenMemo + 1)*/;

	DBF_CHECK_ERROR(
		Read(buffer, nLenMemo) == (UINT)nLenMemo,
		TG_DBF_ERROR_MEMO_FIELD_READ);

	buffer[nLenMemo] = '\0';
	// strMemo.ReleaseBuffer(nLenMemo + 1);
	strMemo = buffer;
	delete [] buffer;
	buffer = NULL;

	nLen = nLenMemo;

// }
// CATCH(CFileException, e)
// {
// 	e->ReportError();
// 	e->Delete();
// 
// 	TGThrowDBFException(TG_DBF_ERROR_MEMO_FIELD_READ);
// 
// } END_CATCH
	return TRUE;
}

BOOL CFPTMemoFile::ReadMemoRecord(DBF_ULONG lOffsetRec, DBF_LONG& nLen, unsigned char** pMemoData)
{
	if (lOffsetRec < 0)
		return FALSE;

	*pMemoData = NULL;

	if(!IsOpen())
		return FALSE;

// TRY
// {
	DBF_LONG  nLenMemo = 0;

	Seek(lOffsetRec * m_nBlockSize + sizeof(DBF_LONG),CFile::begin);

	DBF_CHECK_ERROR(
		Read(&nLenMemo, sizeof(nLenMemo)) == sizeof(DBF_LONG),
		TG_DBF_ERROR_MEMO_FIELD_READ);

	nLenMemo = SWAP_DWORD_BYTE(nLenMemo);

	DBF_CHECK_ERROR(nLenMemo > 0,TG_DBF_ERROR_MEMO_FIELD_READ);

	*pMemoData = new unsigned char[nLenMemo];

	DBF_CHECK_ERROR(
		Read(*pMemoData, nLenMemo) == (UINT)nLenMemo,
		TG_DBF_ERROR_MEMO_FIELD_READ);

	nLen = nLenMemo;

// }
// CATCH(CFileException, e)
// {
// 	e->ReportError();
// 	e->Delete();
// 
// 	TGThrowDBFException(TG_DBF_ERROR_MEMO_FIELD_READ);
// 
// } END_CATCH
	return TRUE;
}

BOOL CFPTMemoFile::WriteMemoRecord(DBF_ULONG& lOffsetRec, DBF_LONG& nLen, CTDbfString& strMemo)
{
	

	if(!IsOpen())
		return FALSE;

// TRY
// {
	DBF_LONG  nLenMemo = 0;

	if(strMemo.IsEmpty())
		lOffsetRec = 0;

	else if(lOffsetRec > 0)
	{
		Seek(lOffsetRec * m_nBlockSize + sizeof(DBF_LONG),CFile::begin);

		DBF_CHECK_ERROR(
			Read(&nLenMemo, sizeof(nLenMemo)) == sizeof(DBF_LONG),
			TG_DBF_ERROR_MEMO_FIELD_READ);

		nLenMemo = SWAP_DWORD_BYTE(nLenMemo);

		nLenMemo = (DBF_LONG) ceil(((double)(nLenMemo + sizeof(DBF_LONG)))/((double)m_nBlockSize)) * m_nBlockSize - sizeof(DBF_LONG);

		if(nLenMemo < (int)strMemo.GetLength())
			lOffsetRec = AddMemoRecord(strMemo);
		else
			UpdateMemoRecord(lOffsetRec, strMemo);
	}
	else
		lOffsetRec = AddMemoRecord(strMemo);

// }
// CATCH(CFileException, e)
// {
// 	e->ReportError();
// 	e->Delete();
// 
// 	TGThrowDBFException(TG_DBF_ERROR_MEMO_FIELD_WRITE);
// 
// } END_CATCH
	return TRUE;
}

DBF_LONG CFPTMemoFile::AddMemoRecord(CTDbfString& strMemo)
{
	DBF_ULONG lOffsetRec = 0;

TRY
{
	DBF_LONG nSign = MF_TEXTREC;
	DBF_LONG nLenMemo = strMemo.GetLength();

	ReadHeader();

	lOffsetRec = m_nNextBlock;
	m_nNextBlock += (DBF_LONG) ceil((double)(nLenMemo + sizeof(nSign)) / (double)m_nBlockSize);
	m_FPTHead.next_block = SWAP_DWORD_BYTE(m_nNextBlock);

	Seek(lOffsetRec * m_nBlockSize,CFile::begin);
		
	nSign = SWAP_DWORD_BYTE(nSign);
	Write(&nSign, sizeof(nSign));

	nLenMemo = SWAP_DWORD_BYTE(nLenMemo);
	Write(&nLenMemo, sizeof(nLenMemo));
		
	Write(strMemo.toLPCSTR(), strMemo.GetLength());


	WriteHeader();

}
CATCH(CFileException, e)
{
	e->ReportError();
	e->Delete();

} END_CATCH

	return lOffsetRec;
}

void CFPTMemoFile::UpdateMemoRecord(DBF_ULONG lOffsetRec, CTDbfString& strMemo)
{

TRY
{
	DBF_LONG nLenMemo = strMemo.GetLength();

	Seek(lOffsetRec * m_nBlockSize + sizeof(DBF_LONG),CFile::begin);
		
	nLenMemo = SWAP_DWORD_BYTE(nLenMemo);
	Write(&nLenMemo, sizeof(nLenMemo));
		
	Write(strMemo.toLPCSTR(), strMemo.GetLength());

}
CATCH(CFileException, e)
{
	e->ReportError();
	e->Delete();

} END_CATCH

}

#ifdef _DEBUG
void CFPTMemoFile::AssertValid() const
{
	CMemoFile::AssertValid();
}

void CFPTMemoFile::Dump(CDumpContext& dc) const
{
	

	CMemoFile::Dump(dc);

	dc << "m_nNextBlock = " << m_nNextBlock;
	dc << "m_nBlockSize = " << m_nBlockSize;

	dc << "\n";
}
#endif //_DEBUG
